#ifndef _GOVT_CHARACTER_H
#define	_GOVT_CHARACTER_H
/*******************************************************************************
 ** Name: character.cpp                                                       **
 ** Description: WorldObject-derived container objects                        **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved License                             **
 **                                                                           **
 ** The contents of this file are subject to the terms of the                 **
 ** Common Development and Distribution License, Version 1.0 only             **
 ** (the "License").  You may not use this file except in compliance          **
 ** with the License.                                                         **
 **                                                                           **
 ** You can find a copy of the license in the LICENSE file within             **
 ** this distribution or at $WIKI/display/GOVT/License-software.              **
 ** Software distributed under the License is distributed on an "AS IS"       **
 ** basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.           **
 ** See the License for the specific language governing permissions           **
 ** and limitations under the License.                                        **
 **                                                                           **
 ** When distributing Covered Code, include this CDDL header in each          **
 ** file and include the License file at $GAME_DIR/LICENSE.                   **
 ** If applicable, add the following below this header, with the indicated    **
 ** fields enclosed by brackets "[]" replaced with your own identifying       **
 ** information: Portions Copyright [yyyy] [name of copyright owner]          **
 **                                                                           **
 **                                                                           **
 ** Copyright (c) 2009-2012  Barry Gian James <gian@gamingods.net>            **
 ** All rights reserved.                                                      **
 ******************************************************************************/
// Modified $Date: 2012-08-14 20:47:30 -0600 (Tue, 14 Aug 2012) $ by $Author: unknown $
#define _character_h_ID    "$Id: character.hpp 69068 2012-08-15 02:47:30Z unknown $"
//#include <boost/intrusive/list.hpp>
#include <falcon/engine.h>
#include <vector>
#include <odb/core.hxx>
#include <string>
#include <boost/shared_ptr.hpp>
#include "object.hpp"
#include "condition.hpp"
#include "faction.hpp"
//#include "agency.hpp"
#include "professions.hpp"
#include "background.hpp"
#include "occupation.hpp"
#include "quest.hpp"
#include "training.hpp"
#include "container.hpp"
#include "visitor.hpp"
#include "common.hpp"
#include "cmd.hpp"
#include "policy.hpp"

#define MAX_CHAR_LVL        200		//!< Wow, 200? Really?
#define MAX_USERNAME_LEN	128
#define MAX_PASSWD_LEN		12
#define DEFAULT_STAT		8

// Character flags
#define	CHAR_AUTOJOIN_CHAN	0x0001
#define CHAR_OOC		0x0002	// is player in character or ooc?
#define CHAR_SUSPECT		0x0004	// report some activity to controls
#define CHAR_CAN_BUILD		0x0008	// a builder
#define CHAR_PVP		0x0010	// char is set pvp
#define CHAR_ALLOW_TELL		0x0020	// player allows whispers
#define CHAR_ALLOW_COLOR_THEMES 0x0040	// allow setting up color themes
#define CHAR_HANDLER		0x0080
#define CHAR_CONTROL		0x0100	// Control
#define CHAR_DIRECTOR		0x0200	// players who manage gameplay and content
#define CHAR_GOD		0x0400	// one and only
#define CHAR_MISSION_CTRL	0x0800	// Mission Control
#define CHAR_AGENCY_CTRL	0x1000	// Agency Control
#define CHAR_GAME_CTRL		0x2000	// Game Control

enum class GenderType { Male, Female, Androgenous, Transgendered };
extern const char * GenderStr[];

struct WearLocations
{
	entity_t	head;
	entity_t	larm;
	entity_t	rarm;
	entity_t	lleg;
	entity_t	rleg;
	entity_t	chest;
	entity_t	back;
	entity_t	feet;
	entity_t	neck;
	entity_t	waist;
	entity_t	lfinger;
	entity_t	rfinger;
	entity_t	legs;
	entity_t	lhand;
	entity_t	rhand;
	entity_t	lwrist;
	entity_t	rwrist;

	WearLocations();
};

// Command/Power Hierarchy
enum class power {
    civilian,   //!< rank 0. guest.
    agent,      //!< rank 1. field agent. most players.
    handler,    //!< rank 2. mission generator.
    control,    //!< rank 3. agency executive.
    director,	//!< rank 4. board of directors sets game policies
    admin       //!< OOC game admin
};

//! General schedule ranks
enum class gs
{
    gs1,        gs2,
    gs3,        gs4,
    gs5,        gs6,
    gs7,        gs8,
    gs9,        gs10,
    gs11,       gs12,
    gs13,       gs14,
    gs15,
    //! Senior Executive Service ranks
    ses1,       ses2,
    ses3,       ses4,

    max
};

// TODO - Maybe remove this.
// Deprecated
enum class Allegience {
	none, self, agency, higher, truth, knowledge, justice
};

class Level
{
public:
	static int	XPNeededForLevel(int l) { return (l*l*1000); }
	static int	XPTillNextLevel(int l, int xp) { return (XPNeededForLevel(l) - xp); }
};

#pragma db value
struct InventoryData
{
	InventoryData() { _id = _owner = _item = 0; }

	#pragma db id auto
	entity_t	_id;
	entity_t	_owner;
	entity_t	_item;
};

class Dossier;
class Agency;
//! @class Character
//! All players are characters.
#pragma db object polymorphic table("character_base")
class Character : public WorldObject
{
public:
    Character();
    explicit Character(const std::string & n);
    Character(const Character& orig);
    ~Character();

    SMART_PTR_DECL(Character)

    static pointer Create(const std::string & n) {
    	return pointer(new Character(n));
    }

    virtual std::string TypeToStr() { return "Character"; }

    const entity_t	Dept() const { return 0; }

    const int		Level() const { return _lvl; }
    void	Level(const int & l) { _lvl = l; }
    const int  XP() const { return _xp; }
    void	XP(const int & x) { _xp = x; }
    const int  Wealth() const { return _scratch; }
    void	Wealth(const int & w) { _scratch = w; }
    const bool  FXSensitive() const { return _fxsensitive; }
    void	FXSensitive(const bool & b) { _fxsensitive = b; }

    const std::string&    Height() const  { return _height; }
    void	Height(const std::string & h) { _height = h; }
    const std::string&    Eyes() const  { return _eyes; }
    void	Eyes(const std::string & e) { _eyes = e; }
    const std::string&    Hair() const  { return _hair; }
    void	Hair(const std::string & h) { _hair = h; }
    const unsigned int &	  Age() const  { return _age; }
    void	Age(const unsigned int & a) { _age = a; }
    const std::string&	  Codename() const  { return _codename; }
    void	Codename(const std::string & c) { _codename = c; }
    const boost::shared_ptr<Agency> &		Faction() const  { return _agency; }
    void 	Faction(const boost::shared_ptr<Agency>& f) { _agency = f; }
    const GenderType &	Gender() const  { return _gender; }
    void	Gender(const GenderType & g) { _gender = g; }

    int		IsControl() { return BMCHK(_flags,CHAR_CONTROL); }
    int		IsHandler() { return BMCHK(_flags,CHAR_HANDLER); }
    int		IsBuilder() { return BMCHK(_flags,CHAR_CAN_BUILD); }
    int		IsGod() { return BMCHK(_flags,CHAR_GOD); }
    int		IsDirector() { return BMCHK(_flags,CHAR_DIRECTOR); }

     void	SetLevel(int l) { _lvl = l; }
    void	IncrLevel() { ++_lvl; }
    double &	Consider() { return _consider; }
   condition &	Condition() { return _cond; }

    int		Actionable();
    void	accept(Pattern::Visitor & v);
    //! Recalculates all stats based on worn, wielded, bkg,occ,prof,etc.
    //! This is an expensive operation. Use with caution.
    void	UpdateStats();

    // The new stat management is in support of ODB ORM ~gian
    // FIXME Figure out what this syntax error is with STR()
    const unsigned int	STRN()	{ return _str; }
    const unsigned int 	DEX() { return _dex; }
    const unsigned int 	CON() { return _con; }
    const unsigned int 	INT() { return _inte; }
    const unsigned int 	WIS() { return _wis; }
    const unsigned int 	CHA() { return _cha; }

    void      setSTR(const unsigned int v) { _str = v; }
    void      setDEX(const unsigned int v) { _dex = v; }
    void      setCON(const unsigned int v) { _con = v; }
    void      setINT(const unsigned int v) { _inte = v; }
    void      setWIS(const unsigned int v) { _wis = v; }
    void      setCHA(const unsigned int v) { _cha = v; }



    const unsigned int 	STRtemp() { return _str_temp; }
    const unsigned int 	DEXtemp() { return _dex_temp; }
    const unsigned int 	CONtemp() { return _con_temp; }
    const unsigned int 	INTtemp() { return _inte_temp; }
    const unsigned int 	WIStemp() { return _wis_temp; }
    const unsigned int 	CHAtemp() { return _cha_temp; }

    void     setSTRtemp(const unsigned int v) { _str_temp = v; }
    void      setDEXtemp(const unsigned int v) { _dex_temp = v; }
    void      setCONtemp(const unsigned int v) { _con_temp = v; }
    void      setINTtemp(const unsigned int v) { _inte_temp = v; }
    void     setWIStemp(const unsigned int v) { _wis_temp = v; }
    void      setCHAtemp(const unsigned int v) { _cha_temp = v; }

    int 	STRbonus() { return _str_bonus; }
    int 	DEXbonus() { return _dex_bonus; }
    int 	CONbonus() { return _con_bonus; }
    int 	INTbonus() { return _inte_bonus; }
    int 	WISbonus() { return _wis_bonus; }
    int 	CHAbonus() { return _cha_bonus; }

    void      setSTRbonus(int v) { _str_bonus = v; }
    void       setDEXbonus(int v) { _dex_bonus = v; }
    void       setCONbonus(int v) { _con_bonus = v; }
    void       setINTbonus(int v) { _inte_bonus = v; }
    void      setWISbonus(int v) { _wis_bonus = v; }
    void       setCHAbonus(int v) { _cha_bonus = v; }

    const unsigned int 	DEF() { return _def; }
    const unsigned int 	AVD() { return _avd; }
    const unsigned int 	INIT() { return _init; }

    const unsigned int 	DEFtemp() { return _def_temp; }
    const unsigned int 	AVDtemp() { return _avd_temp; }
    const unsigned int 	INITtemp() { return _init_temp; }

    const unsigned int 	Fort() { return _fort; }
    const unsigned int 	Will() { return _will; }
    const unsigned int 	Reflex() { return _reflex; }
    const unsigned int 	Recovery() { return _recovery; }

    void      setDEF(const unsigned int v) { _def = v; }
    void      setAVD(const unsigned int v) { _avd = v; }
    void      setINIT(const unsigned int v) { _init = v; }

    void      setDEFtemp(const unsigned int v) { _def_temp = v; }
    void      setAVDtemp(const unsigned int v) { _avd_temp = v; }
    void      setINITtemp(const unsigned int v) { _init_temp = v; }

    void      setFort(const unsigned int v) { _fort = v; }
    void      setWill(const unsigned int v) { _will = v; }
    void      setReflex(const unsigned int v) { _reflex = v; }
    void      setRecovery(const unsigned int v) { _recovery = v; }


    const std::string & TitlePrefix() const { return _title_prefix; }
    void	TitlePrefix(const std::string & t) { _title_prefix = t; }
    const std::string & TitleSuffix() const { return _title_suffix; }
    void	TitleSuffix(const std::string & t) { _title_suffix = t; }

	// Quests
	bool		QuestCompleted(std::string &);
	void		AddQuest(entity_t);
	void		CompleteQuest(entity_t);

//	// Commands
//	void		AddCmd(boost::shared_ptr<Command> & c) { commands.push_back(c); }
//	void		DelCmd(std::string &);
//	boost::shared_ptr<Command> & GetCmd(std::string &);

    // TODO Figure out how to set wielding/wield items in left/right hand
    // and get the item wielded from either or both hands.
	bool		Wielding();
	WearLocations & WearLocation() { return _wearLocations; }

    // Inventory
    std::vector<boost::shared_ptr<InventoryData> > &	Inventory() { return _inventory; }
    entity_t			FindInventoryItem(std::string);
    void			RemoveInventoryItem(entity_t);
    void			AddInventoryItem(entity_t);	//!< don't forget to check encumbrance when adding to inventory

private:
    friend class odb::access;
    std::string	_codename;
    std::string    _height;
    std::string    _eyes;
    std::string    _hair;
    unsigned int		_age;
    GenderType		_gender;

    // Change in support of ODB ORM types. ~gian
    unsigned int		_str,_dex,_con,_inte,_wis,_cha;
    unsigned int		_str_temp,_dex_temp,_con_temp,_inte_temp,_wis_temp,_cha_temp;
    int		_str_bonus,_dex_bonus,_con_bonus,_inte_bonus,_wis_bonus,_cha_bonus;

    unsigned int		_def,_avd,_init,_speed;
    unsigned int		_def_temp, _avd_temp, _init_temp,_speed_temp;

    unsigned int		_fort,_will,_reflex,_recovery;

//    BaseStat    _base;       //!< str,dex,con,int,wis,cha
//    DerivedStat _derived;    //!< def,speed,init,bab,etc
//    SavingThrow _saves;      //!< fort,reflex,will,recovery

    ulong  _xp;	// int max = 4.2B
    ulong	_scratch;
    int     _lvl;    //!< career level (ie 3)
    bool    _fxsensitive; //!< astral-sensitive
    double	_consider;	// this is what 'consider' compares.
    int		_flags;

    boost::shared_ptr<Agency>	_agency;

    // Condition
    condition	_cond;

    std::string		_title_prefix;
    std::string		_title_suffix;

    std::vector<boost::shared_ptr<InventoryData> >	_inventory;

	WearLocations	_wearLocations;

	// Policies are the logic modules that govern how events will be handled
	std::vector<boost::shared_ptr<Policy> > _policies;

//	std::vector<boost::shared_ptr<Command> > commands;
};

// Design RC-0.1
#pragma db object table("characters")
class PC : public Character
{
public:
	SMART_PTR_DECL(PC);

	PC();
	PC(const std::string & n);
	PC(const PC &);

	void	accept(Pattern::Visitor & v);

    // Getters
    const std::string& Profession() const { return _profession; }
    const std::string& Background() const { return _background; }
    const std::string& Occupation() const { return _occupation; }
    const unsigned int BackgroundLevel() const { return _bkglvl; }
    const entity_t		Rank() const { return _rank; }
    const int			PlayerKills() const { return _pkills; }
    const int			PlayerDeaths() const { return _pdeaths; }
    const unsigned int	Encumbrance() const { return _encumbranceCurr; }
    const unsigned int	EncumbranceMax() const { return _encumbranceMax; }
    const unsigned int	EncumbrancePct() const { return _encumbrancePct; }
    const int   Renown() const { return _renown; }
    const int	Liability() const { return _liability; }
    const int	Capital() const { return _capital; }
    const agency::deptnum Dept() const { return _dept; }
    const int &	Wanted() const { return _wanted; }

    // Setters
    void	Wanted(const int w) { _wanted = w; }
    void	Renown(const int & r) { _renown = r; }
    void	Liability(const int l) { _liability = l; }
    void	Capital(const int c) { _capital = c; }
    void	Profession(const std::string & p) { _profession = p; }
    void	Background(const std::string & b) { _background = b; }
    void	Occupation(const std::string & o) { _occupation = o; }
    void	BackgroundLevel(const unsigned int b) { _bkglvl = b; }
    void	Rank(const entity_t r) { _rank = r; }
    void	PlayerKills(const int pk) { _pkills = pk; }
    void	PlayerDeaths(const int pd) { _pdeaths = pd; }
    void	Encumbrance(const unsigned int e) {_encumbranceCurr = e; }
    void	EncumbranceMax(const unsigned int e) { _encumbranceMax = e; }
    void	EncumbrancePct(const unsigned int e ) { _encumbrancePct = e; }
    void	Dept(const agency::deptnum d) { _dept = d; }

private:
    friend class odb::access;

	std::string		_profession;
	std::string		_background;
	std::string		_occupation;
	unsigned int			_bkglvl;
	entity_t		_rank;		// faction rank
    int		_pkills;		//!< number of player kills
    int		_pdeaths;		//!< number of deaths
#pragma db column("encumbrance_curr")
    unsigned int	_encumbranceCurr;
#pragma db column("encumbrance_pct")
    unsigned int	_encumbrancePct;
#pragma db column("encumbrance_max")
    unsigned int	_encumbranceMax;
    int     _renown;
    int		_liability;
    int		_capital;
    int		_wanted;

    agency::deptnum _dept;
    
	// TODO Pull the list of titles dynamically from DB with Titles()
	#pragma db unordered
    std::vector<std::string> _titles;
	boost::shared_ptr<Dossier> _dossier;

};


//! @class Dossier
//! @brief A character's dossier
//! Top-level class that holds and is responsible for memory of all characters
//! that are online.
class Dossier
{
public:
	Dossier(entity_t a) { _agent = a; }

	entity_t 	Agent() { return _agent; }

	std::vector<std::string> CompletedQuests();
	std::vector<Quest::pointer> CurrentQuests();
	std::vector<std::string> Awards();

private:
    entity_t	_agent;
};



#endif	/* _GOVT_CHARACTER_H */

